#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>

#include "hiseg.h"
#include "charset.h"
#include "mylog.h"

static struct list_head segger_list;
static dat * datp;
static ctx * ctxp;
static ctx * nrp;
static ctx * nsp;
static ctx * trp;
static unsigned char binit = 0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

#define HI_DICT	"hidict.dat"
#define CTX_UN	"unknown.ctx"
#define CTX_NR	"nr.ctx"
#define CTX_NS	"ns.ctx"
#define CTX_TR	"tr.ctx"
int init(const char * base_path)
{
	if(binit != 0){
		return 1;
	}
	if(base_path == NULL){
		return -1;
	}
	char path[128] = {0};
	snprintf(path, 128, "%s/%s", base_path, HI_DICT);
	datp = dat_new();
    if(datp == NULL){
        return -2;
    }
    int ret = dat_load(datp, path);
    if(ret < 0){
        return -3;
    }
	snprintf(path, 128, "%s/%s", base_path, CTX_UN);
	ctxp = ctx_new();
    if(ctxp == NULL){
        return -4;
    }
    ret = ctx_load(ctxp, path);
    if(ret < 0){
        return -5;
    }
	snprintf(path, 128, "%s/%s", base_path, CTX_NR);
	nrp = ctx_new();
    if(nrp == NULL){
        return -6;
    }
    ret = ctx_load(nrp, path);
    if(ret < 0){
        return -7;
    }
	snprintf(path, 128, "%s/%s", base_path, CTX_NS);
	nsp = ctx_new();
    if(nsp == NULL){
        return -8;
    }
    ret = ctx_load(nsp, path);
    if(ret < 0){
        return -9;
    }
	snprintf(path, 128, "%s/%s", base_path, CTX_TR);
	trp = ctx_new();
    if(trp == NULL){
        return -10;
    }
    ret = ctx_load(trp, path);
    if(ret < 0){
        return 6;
    }

	init_codemap();
	INIT_LIST_HEAD(&segger_list);
	binit = 1;
	return 0;
}

int gen_dict(const char * dict_utf8, const char * dict_path)
{
	if(binit == 0 || dict_utf8 == NULL || dict_path == NULL){
		return -1;
	}
	datp = dat_new();
    if(datp == NULL){
        return -2;
    }
	int ret = dat_dump(datp, dict_utf8, dict_path);
	if(ret < 0){
		dat_free(datp);
		return -3;
	}
	dat_free(datp);
	return 0;
}

unsigned long get_segger()
{
	if(binit == 0){
		return 0;
	}
	//lock !!!!!!!!!!!!!!!!!
	pthread_mutex_lock(&mutex);
	segger * s = NULL;
	if(!list_empty(&segger_list)){
		s = list_entry(segger_list.prev, segger, list);	//get from tail
		if(s->busy == SEGER_FREE){
			list_del(&s->list);
		}else{
			s = NULL;
		}
	}
	if(s == NULL){
		s = segger_new(datp, ctxp, nrp, nsp, trp);
	}
	if(s == NULL){
		return 0;
	}
	s->busy = SEGER_BUSY;
	list_add(&s->list, &segger_list);				//busy node add head
	pthread_mutex_unlock(&mutex);
	return (unsigned long)s;
}

int return_segger(unsigned long key)
{
	if(binit==0 || key == 0){
		return -1;
	}
	pthread_mutex_lock(&mutex);
	segger * s = (segger *)key;
	s->busy = SEGER_FREE;
	list_del(&s->list);
	list_add_tail(&s->list, &segger_list);		//free node add tail
	pthread_mutex_unlock(&mutex);
	return 0;
}

int destroy()
{
	if(binit == 0){
		return 1;
	}
	struct list_head * l = NULL;
	segger * s = NULL;
	list_for_each(l, &segger_list){
		s = list_entry(l, segger, list);
		l = l->prev;
		list_del(&s->list);
		segger_free(s);
	}
	dat_free(datp);
	free_codemap();
	binit = 0;
	return 0;
}

int hiseg_do(unsigned long key, char * input, unsigned int len)
{
	if(binit == 0){
		return -1;
	}
	return segger_do((segger *)key, input, len);
}

int hiseg_next_res(unsigned long key, char * buf, unsigned int buflen)
{
	if(binit == 0){
		return -1;
	}
	unsigned int len = 0;
	const char * res = segger_next_res((segger *)key, &len);
	if(res == NULL){
		return 0;
	}
	strncpy(buf, res, buflen>len?len:(buflen-1));
	buf[((buflen>len)?len:(buflen-1))] = '\0';
	return len;
}

#ifdef HISEG_MAIN
int main(int argc, char ** argv)
{
	LOGON("stderr");
	int ret = init("/home/aaron/workspace/hiseg/clasdict/");
	if(ret < 0){
		return -1;
	}
	unsigned s = get_segger();
	if(s == 0){
		return -2;
	}
	char * buf = "成为了20";
	if(hiseg_do(s, buf, strlen(buf)) < 0){
		return -12;
	}
	char out[1024] = {0};
	while(hiseg_next_res(s, out, 1024) > 0){
		printf("%s ", out);
	}
	printf("\n");
	return_segger(s);
	destroy();
	LOGOFF();
	return 0;
}
#endif
